from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView,ListAPIView,RetrieveAPIView,UpdateAPIView,DestroyAPIView

from rest_framework.views import APIView
from api import models

from django.forms import model_to_dict

#状态码
from rest_framework import status

from django.db.models import F

from  rest_framework import exceptions

from utils.auth import GeneralAuthentication,UserAuthentication,SchoolTopicUserAuthentication


from django.template.defaultfilters import  date as django_dateformat


class NewsModelSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    topic = serializers.SerializerMethodField()

    class Meta:
        model = models.News
        fields = ['id','cover','content','topic','user','favor_count']

    def get_user(self,obj):
        # return {"id":obj.user_id,"nickname":obj.user.nickname,"avatar":obj.user.avatar}
        return model_to_dict(obj.user,fields=['id','nickname','avatar'])

    def get_topic(self,obj):
        if not obj.topic:
            return

        # return {"id":obj.topic_id,"title":obj.topic.title}
        return model_to_dict(obj.topic,fields=['id','title'])





# class NewsView(APIView):
#
#     def get(self,request,*args,**kwargs):
#         min_id = request.query_params.get('min_id')
#         max_id = request.query_params.get('max_id')
#
#
#         if min_id:
#             queryset = models.News.objects.filter(id__lt=min_id).order_by('-id')[0:10]
#         elif max_id:
#             queryset = models.News.objects.filter(id__gt=max_id).order_by('id')[0:10]
#         else:
#             queryset = models.News.objects.all().order_by('-id')[0:10]
#
#         ser = NewsModelSerializer(instance=queryset,many=True)
#         return Response(ser.data,status=200)



# #引入分页器
# from rest_framework.pagination import LimitOffsetPagination
#
# #处理下拉刷新和上拉翻页
# from rest_framework.filters import BaseFilterBackend
#
#
# class OldBoyLimitPagination(LimitOffsetPagination):
#     """
#     本质上帮助我们进行切片的处理[0:N]
#     """
#     #默认切多少条数据
#     default_limit = 5
#     #最多切多少条
#     max_limit = 50
#     #通过前端传过来的参数 limit 控制切多少条数据
#     limit_query_param = 'limit'
#
#     #从第几条数据开始取(不使用，重写 get_offset 函数使其无效)
#     offset_query_param = 'offset'
#     #定制起始位置
#     def get_offset(self, request):
#         return 0
#
#     #定制页面展示的数据格式
#     def get_paginated_response(self, data):
#         return Response(data)
#
#
#
#
#
# #上拉翻页，获取之前的数据
# class MinFilterBackend(BaseFilterBackend):
#     def filter_queryset(self, request, queryset, view):
#         min_id = request.query_params.get('min_id')
#         if min_id:
#             return queryset.filter(id__lt=min_id).order_by('-id')
#
#         return queryset
#
#
# #下拉刷新，取最新的数据
# class MaxFilterBackend(BaseFilterBackend):
#     def filter_queryset(self, request, queryset, view):
#         max_id = request.query_params.get('max_id')
#         if max_id:
#             return queryset.filter(id__gt=max_id).order_by('id')
#
#         return queryset



from utils.pagination import OldBoyLimitPagination
from utils.filters import MinFilterBackend,MaxFilterBackend





class CreateNewsImageListModelSerializer(serializers.Serializer):
    key = serializers.CharField()
    cos_path = serializers.CharField()


class CreateNewsModelSerializer(serializers.ModelSerializer):
    imageList = CreateNewsImageListModelSerializer(many=True)

    class Meta:
        model = models.News
        exclude = ['user','viewer_count','commment_count','favor_count']


    def create(self, validated_data):
        image_list = validated_data.pop('imageList')
        news_object = models.News.objects.create(**validated_data)
        data_list = models.NewsDetail.objects.bulk_create(
            [models.NewsDetail(**info,news=news_object) for info in image_list]
        )

        if news_object.topic:
            topic_object = news_object.topic
            topic_object.count += 1
            topic_object.save()

        if news_object.school:
            school_object = news_object.school
            school_object.count += 1
            school_object.save()

        news_object.imageList = data_list

        return news_object










###查看动态列表接口
###发布接口
#####################处理动态信息#########################
class NewsView(ListAPIView,CreateAPIView):
    queryset = models.News.objects.all().order_by('-id')

    pagination_class = OldBoyLimitPagination

    filter_backends = [MinFilterBackend,MaxFilterBackend]



    def perform_create(self, serializer):
        #只能保存News表中的数据()
        #调用serializer对象的save(先调用create),通过重写create,完成其他数据的保存
        news_object = serializer.save(user=self.request.user)
        return news_object


    def get_serializer_class(self):
        if self.request.method == 'GET':
            return NewsModelSerializer
        if self.request.method == 'POST':
            return CreateNewsModelSerializer

    def get_authenticators(self):
        if self.request.method == 'POST':
            return [SchoolTopicUserAuthentication(),]






class TopicModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Topic
        fields = "__all__"



#####################处理话题信息#########################
class TopicView(ListAPIView):
    serializer_class = TopicModelSerializer
    queryset = models.Topic.objects.all().order_by('-id')

    # pagination_class = OldBoyLimitPagination

    # filter_backends = [MinFilterBackend,MaxFilterBackend]






class NewsDetailModelSerializer(serializers.ModelSerializer):
    images = serializers.SerializerMethodField()
    # create_date = serializers.SerializerMethodField()
    create_date = serializers.DateTimeField(format="%Y-%m-%d")
    user = serializers.SerializerMethodField()
    topic = serializers.SerializerMethodField()
    viewer = serializers.SerializerMethodField()
    comment = serializers.SerializerMethodField()

    is_favor = serializers.SerializerMethodField()
    is_follow = serializers.SerializerMethodField()
    school = serializers.SerializerMethodField()


    class Meta:
        model = models.News
        # fields = "__all__"
        exclude = ['cover',]

    def get_images(self,obj):
        #找到当前新闻的所有图片对象
        detail_queryset =  models.NewsDetail.objects.filter(news = obj)

        # return [{'id':row.id,'path':row.cos_path} for row in detail_queryset]
        return [model_to_dict(row,['id','cos_path']) for row in detail_queryset]

    # def get_create_date(self,obj):
    #     return obj.create_date.strftime("%Y-%m-%d")



    def get_school(self,obj):
        if not obj.school:
            return
        return model_to_dict(obj.school)

    def get_topic(self,obj):
        if not obj.topic:
            return
        return model_to_dict(obj.topic,fields=['id','title'])

    def get_user(self,obj):
        return model_to_dict(obj.user,fields=['id','nickname','avatar'])

    #获取访客记录
    def get_viewer(self,obj):
        #根据动态对象查询所有访客
        queryset =  models.ViewerRecord.objects.filter(news=obj)
        viewer_object_list = queryset.order_by('-id')[0:6]
        context = {
            'count':queryset.count(),
            'result':[model_to_dict(item.user,['nickname','avatar'])  for item in viewer_object_list]
        }

        return context

        # return [model_to_dict(item.user,['nickname','avatar'])   for item in viewer_queryset]

    def get_comment(self,obj):
        """
        获取所有的一级评论，再给每个一级评论获取一个二级评论
        """

        #1.获取所有的一级评论
        first_queryset =  models.CommentRecord.objects.filter(news=obj,depth=1).order_by('-id')[0:10].values(
            'id',
            'content',
            'depth',
            'user__nickname',
            'user__avatar',
            'create_date'
        )

        for item in first_queryset:
            item['create_date'] = item['create_date'].strftime('%Y-%m-%d')


        #2.获取所有的二级评论
        # second_query = models.CommentRecord.objects.filter(news=obj,depth=2)

        #2.获取所有一级评论下的二级评论
        # first_id_list = [item['id'] for item in first_queryset]
        # second_query = models.CommentRecord.objects.filter(news=obj,depth=2,reply_id__in=first_id_list)

        #2.获取所有一级评论下的二级评论(每个二级评论只最新的取一条)
        from django.db.models import Max
        first_id_list = [item['id'] for item in first_queryset]
        #取到指定所有一级评论下的二级评论，并根据reply_id进行分组，在每个分组中提取id最大的那一条记录(最新的一条回复记录)
        #这段代码返回的只有两个字段:reply_id和max_id
        result = models.CommentRecord.objects.filter(news=obj,depth=2,reply_id__in=first_id_list).values('reply_id').annotate(max_id=Max('id'))
        second_id_list = [item['max_id']  for item in result]  #5,8

        #最终符合条件的二级评论的记录
        second_queryset = models.CommentRecord.objects.filter(id__in=second_id_list).values(
            'id',
            'content',
            'depth',
            'user__nickname',
            'user__avatar',
            'create_date',
            'reply_id',
            'reply__user__nickname'
        )

        for item in second_queryset:
            item['create_date'] = item['create_date'].strftime('%Y-%m-%d')


        #######创建一个有序字典#########(自动根据字典里键值对的键的值进行倒排)
        import collections
        first_dict = collections.OrderedDict()
        for item in first_queryset:
            item['child'] = []
            first_dict[item['id']] = item

        for item in second_queryset:
            first_dict[item['reply_id']]['child'] = [item,]



        return first_dict.values()


    def get_is_favor(self,obj):
        #1.用户未登录
        user_object = self.context['request'].user
        if not user_object:
            return False

        #2.用户已登录
        exists = models.NewsFavorRecord.objects.filter(user=user_object,news=obj).exists()
        return exists


    def get_is_follow(self,obj):
        #1.判断用户是否已经登录
        user_object = self.context['request'].user
        if not user_object:
            return False

        exists = models.UserSubmit.objects.filter(user=user_object,beuser=obj.user).exists()

        return exists




#####################处理动态详细信息#########################
           ###RetrieveAPIView只帮我们取一条数据
class NewsDetailView(RetrieveAPIView):
    queryset = models.News.objects

    serializer_class = NewsDetailModelSerializer
    ###认证组件已经在全局配置上了，具体看settings文件
    # authentication_classes = [GeneralAuthentication,]

    def get(self,request,*args,**kwargs):
        response = super().get(request,*args,**kwargs)
        #如果用户已登录，在访问记录中添加一条记录
        #去Authorization的请求头中获取token
        if not request.user:
            return response
        #校验数据库中是否存在这条动态记录(如果不存在则报异常，代码不再往下走)
        news_object = self.get_object() #models.News.object.get(pk=pk)

        #在判断当前用户是否有访问此新闻的记录
        exists = models.ViewerRecord.objects.filter(user=request.user,news=news_object).exists()
        if exists:
            return response

        models.ViewerRecord.objects.create(user=request.user,news=news_object)
        models.News.objects.filter(id=news_object.id).update(viewer_count=F('viewer_count')+1)

        return response










class CommentModelSerializer(serializers.ModelSerializer):
    create_date = serializers.DateTimeField(format="%Y-%m-%d")
    user__nickname = serializers.CharField(source="user.nickname")
    user__avatar = serializers.CharField(source="user.avatar")
    reply_id = serializers.CharField(source="reply.id")
    reply__user__nickname = serializers.CharField(source="reply.user.nickname")

    class Meta:
        model = models.CommentRecord
        exclude = ['news','user','reply','root']




class CreateCommentModelSerializer(serializers.ModelSerializer):
    create_date = serializers.DateTimeField(format="%Y-%m-%d",read_only=True)
    user__nickname = serializers.CharField(source="user.nickname",read_only=True)
    user__avatar = serializers.CharField(source="user.avatar",read_only=True)
    reply_id = serializers.CharField(source="reply.id",read_only=True)
    reply__user__nickname = serializers.CharField(source="reply.user.nickname",read_only=True)

    class Meta:
        model = models.CommentRecord
        exclude = ['user','favor_count']



######################"GET"获取所有子评论()###################
######################"POST"发布一条评论()###################
class CommentView(APIView):

    def get_authenticators(self):
        if self.request.method == 'POST':
            return [UserAuthentication(),]

        return [GeneralAuthentication(),]


    def get(self,request,*args,**kwargs):
        root_id = request.query_params.get('root')

        #1.获取这个根评论的所有子孙评论
        node_queryset = models.CommentRecord.objects.filter(root_id=root_id).order_by('id')

        #2.序列化
        ser = CommentModelSerializer(instance=node_queryset,many=True)

        return Response(ser.data,status=status.HTTP_200_OK)



    def post(self,request,*args,**kwargs):
        #1.进行数据校验(news/depth/reply/content/root)
        ser = CreateCommentModelSerializer(data=request.data)

        if ser.is_valid():
            #保存到数据库
            #获取当前登录(评论)用户的信息
            user_object = request.user
            ser.save(user=user_object)
            #对新增到的数据值进行序列化(数据格式需要调整)
            news_id = ser.data.get('news')
            models.News.objects.filter(id=news_id).update(commment_count=F('commment_count')+1)
            #创建成功使用201状态码
            return Response(ser.data,status=status.HTTP_201_CREATED)
                                            #客户端的数据有问题400状态码
        return Response(ser.errors,status=status.HTTP_400_BAD_REQUEST)

        #2.检验通过，保存到数据库

        #3.将保存到数据库的数据再返回给小程序页面(小程序需要在页面上进行展示)



class TestSER(serializers.ModelSerializer):
    xx = serializers.SerializerMethodField()

    class Meta:
        model = models.Topic
        fields = "__all__"

    def get_xx(self,obj):
        #获取request ,request.user
        self.context['request'].user
        return 123

class TestView(ListAPIView):
    queryset = models.Topic.objects

    serializer_class = TestSER



#########################动态点赞######################


class FavorModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.NewsFavorRecord
        fields = ['news']


class FavorView(APIView):

    authentication_classes = [UserAuthentication,]
    def post(self,request,*args,**kwargs):
        ser = FavorModelSerializer(data=request.data)
        if not ser.is_valid():
            return Response({},status=status.HTTP_400_BAD_REQUEST)
        #注意，这里会自动通过Id找到对象
        news_object = ser.validated_data.get('news')
        queryset = models.NewsFavorRecord.objects.filter(user=request.user,news=news_object)
        exists = queryset.exists()
        if exists:
            queryset.delete()
            news_object.favor_count -= 1
            news_object.save()
            return Response({},status=status.HTTP_200_OK)

        models.NewsFavorRecord.objects.create(user=request.user,news=news_object)
        news_object.favor_count += 1
        news_object.save()
        return Response({},status=status.HTTP_201_CREATED)




##########订阅用户#############


class FollowUserModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserSubmit
        fields = ['beuser']


class FollowUser(APIView):

    authentication_classes = [UserAuthentication,]
    def post(self,request,*args,**kwargs):
        ser = FollowUserModelSerializer(data = request.data)
        if not ser.is_valid():
            print(ser.errors)
            return Response({"message":"请求出错!"},status=status.HTTP_400_BAD_REQUEST)
        beuser = ser.validated_data.get('beuser')

        if request.user == beuser:
            return Response({"message":"不能关注自己吖"},status=status.HTTP_400_BAD_REQUEST)

        user_object = request.user
        query_set = models.UserSubmit.objects.filter(user=user_object,beuser=beuser)
        exists = query_set.exists()
        if exists:
            user_object.submit_count -= 1
            beuser.fans_count -= 1
            user_object.save()
            beuser.save()
            query_set.delete()
            return Response({},status=status.HTTP_200_OK)

        models.UserSubmit.objects.create(user=user_object,beuser=beuser)
        user_object.submit_count += 1
        beuser.fans_count += 1
        user_object.save()
        beuser.save()

        return Response({},status=status.HTTP_201_CREATED)




class MeNewsModelSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    create_date = serializers.DateTimeField(format="%Y-%m-%d")
    class Meta:
        model = models.News
        fields = "__all__"

    def get_user(self,obj):
        return model_to_dict(obj.user,fields=['nickname','avatar'])



class MeNews(APIView):

    def get(self,request,*args,**kwargs):
        query_set = models.News.objects.filter(user=request.user).order_by('-id')
        ser = MeNewsModelSerializer(instance=query_set,many=True)
        return Response(ser.data,status=status.HTTP_200_OK)










###################对动态做修改################



# class GetModifyNewsModelSerializer(serializers.ModelSerializer):
#     imageList = serializers.SerializerMethodField()
#     topic = serializers.SerializerMethodField()
#     class Meta:
#         model = models.News
#         fields = "__all__"
#
#     def get_imageList(self,obj):
#         imageList = models.NewsDetail.objects.filter(news=obj)
#         return [model_to_dict(item,fields=['cos_path','key']) for item in imageList]
#
#     def get_topic(self,obj):
#         topic = models.Topic.objects.filter(id=obj.topic.id).first()
#         return model_to_dict(topic,fields=['id','title'])
#
#
# class GetModifyNewsView(RetrieveAPIView,UpdateAPIView):
#     queryset = models.News.objects
#
#     authentication_classes = [UserAuthentication,]
#
#
#     def get_serializer_class(self):
#         if self.request.method == 'GET':
#             return GetModifyNewsModelSerializer
#
#
#





###############获取学校###################

class schoolModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.SchoolArea
        fields = "__all__"


class schoolView(ListAPIView):
    queryset = models.SchoolArea.objects

    serializer_class = schoolModelSerializer





#################综合筛选################


class SearchModelSerializer(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    topic = serializers.SerializerMethodField()
    school = serializers.SerializerMethodField()
    class Meta:
        model = models.News
        exclude = ["address"]

    def get_user(self,obj):
        return model_to_dict(obj.user)

    def get_topic(self,obj):
        if not obj.topic:
            return
        return model_to_dict(obj.topic)

    def get_school(self,obj):
        if not obj.school:
            return
        return model_to_dict(obj.school)

class SearchView(APIView):

    def get(self,request,*args,**kwargs):
        dataset = request.query_params
        content = dataset.get('content')
        topic =dataset.get('topic')
        school = dataset.get('school')
        #########发布的类型(0表示分享,1表示寻找)###########
        deal_status = dataset.get('deal_status')
        if school == "undefined" and topic == "undefined":
            query_set = models.News.objects.filter(content__icontains=content,deal_status=deal_status).order_by('id')
        elif school == "undefined":
            topic_object = models.Topic.objects.filter(id=topic).first()
            topic_object.search_count += 1
            topic_object.save()
            query_set = models.News.objects.filter(topic_id=topic,content__icontains=content,deal_status=deal_status).order_by('id')
        elif topic == "undefined":
            school_object = models.SchoolArea.objects.filter(id=school).first()
            school_object.search_count += 1
            school_object.save()
            query_set = models.News.objects.filter(school_id=school,content__icontains=content,deal_status=deal_status).order_by('id')
        else:
            topic_object = models.Topic.objects.filter(id=topic).first()
            topic_object.search_count += 1
            topic_object.save()

            school_object = models.SchoolArea.objects.filter(id=school).first()
            school_object.search_count += 1
            school_object.save()

            query_set = models.News.objects.filter(topic_id=topic,school_id=school,content__icontains=content,deal_status=deal_status).order_by('id')

            
        ser = SearchModelSerializer(instance=query_set,many=True)
        return Response(ser.data,status=status.HTTP_200_OK)





###############删除动态##############


class newsDeleteView(DestroyAPIView):
    authentication_classes = [UserAuthentication,]
    queryset = models.News.objects


    def perform_destroy(self, instance):
        user_object = instance.user
        if self.request.user != user_object:
            print("用户没有删除权限!")
            raise exceptions.MethodNotAllowed
        print("删除对象:",instance)
        instance.delete()




############搜索学校############


class searchSchoolModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.SchoolArea
        fields = "__all__"


class searchSchoolView(APIView):

    def get(self,request,*args,**kwargs):
        value = request.query_params.get('value')
        query_set = models.SchoolArea.objects.filter(school__icontains=value)
        ser = searchSchoolModelSerializer(instance=query_set,many=True)
        return Response(ser.data,status=status.HTTP_200_OK)
